package org.yunai.swjg.server.module.battle.unit;

import org.yunai.swjg.server.core.role.AbstractRole;
import org.yunai.swjg.server.module.battle.BattleUtils;
import org.yunai.swjg.server.module.battle.operation.BaseBattleOperation;
import org.yunai.swjg.server.module.battle.vo.BattleAction;
import org.yunai.swjg.server.module.battle.vo.BattleUnitAction;
import org.yunai.swjg.server.module.player.template.VocationTemplate;
import org.yunai.swjg.server.module.skill.SkillDef;
import org.yunai.swjg.server.module.skill.template.SkillImpactInfoVO;
import org.yunai.swjg.server.module.skill.template.SkillTemplate;
import org.yunai.yfserver.util.MathUtils;

import java.util.*;

/**
 * 战斗单元
 * User: yunai
 * Date: 13-5-23
 * Time: 下午4:39
 */
public class BattleUnit {

    /**
     * 战斗单元编号
     */
    private final int unitIndex;
    /**
     * 所处行
     */
    private final int unitHang;
    /**
     * 队伍类型
     */
    private final BattleTeam team;
    /**
     * 名字
     */
    private String name;
    /**
     * 等级
     */
    private short level;

    // ==================== 战斗单元最初数值属性 ====================
    /**
     * 普通攻击
     */
    private int baseStrengthAttack;
    /**
     * 绝技攻击
     */
    private int baseStuntAttack;
    /**
     * 法术攻击
     */
    private int baseMagicAttack;
    /**
     * 普通防御
     */
    private int baseStrengthDefense;
    /**
     * 绝技防御
     */
    private int baseStuntDefense;
    /**
     * 法术防御
     */
    private int baseMagicDefense;
    /**
     * 最大血量
     */
    private int baseHpMax;
    /**
     * 暴击，万分比
     */
    private int baseCrit;
    /**
     * 命中，万分比
     */
    private int baseHit;
    /**
     * 破击，万分比
     */
    private int basePoJi;
    /**
     * 必杀，万分比
     */
    private int baseBiSha;
    /**
     * 韧性，万分比
     */
    private int baseToughness;
    /**
     * 闪避，万分比
     */
    private int baseDodge;
    /**
     * 格挡，万分比
     */
    private int baseBlock;

    // ==================== 战斗中计算后战斗数值属性 ====================
    /**
     * 当前血量
     */
    private int hpCur;
    /**
     * 当前士气
     */
    private int moraleCur;
    /**
     * 普通攻击
     */
    private int strengthAttack;
    /**
     * 绝技攻击
     */
    private int stuntAttack;
    /**
     * 法术攻击
     */
    private int magicAttack;
    /**
     * 普通防御
     */
    private int strengthDefense;
    /**
     * 绝技防御
     */
    private int stuntDefense;
    /**
     * 法术防御
     */
    private int magicDefense;
    /**
     * 最大血量
     */
    private int hpMax;
    /**
     * 暴击，万分比
     */
    private int crit;
    /**
     * 命中，万分比
     */
    private int hit;
    /**
     * 破击，万分比
     */
    private int poJi;
    /**
     * 必杀，万分比
     */
    private int biSha;
    /**
     * 韧性，万分比
     */
    private int toughness;
    /**
     * 闪避，万分比
     */
    private int dodge;
    /**
     * 格挡，万分比
     */
    private int block;

    // ==================== 其他属性 ====================
    /**
     * 职业攻击
     */
    private SkillTemplate vocationSkill;
    /**
     * 绝技
     */
    private SkillTemplate specialSkill;

    // ==================== 战斗中Buff/Debuff/Hot/Dot等 ====================
    /**
     * 技能效果集合
     */
    private Map<SkillImpactInfoVO, Integer> continualImpacts;
    /**
     * 临时技能效果集合
     */
    private Map<SkillImpactInfoVO, Integer> tempImpacts;
    /**
     * Buff/Debuff的值集合
     */
    private Map<SkillDef.Effect, Integer> buffDebuffValues;

    public int getBaseHpMax() {
        return baseHpMax;
    }

    public void setBaseHpMax(int baseHpMax) {
        this.baseHpMax = baseHpMax;
    }

    public int getHpCur() {
        return hpCur;
    }

    public void setHpCur(int hpCur) {
        this.hpCur = hpCur;
    }

    public int getHpMax() {
        return hpMax;
    }

    public void setHpMax(int hpMax) {
        this.hpMax = hpMax;
    }

    public int getUnitIndex() {
        return unitIndex;
    }

    public int getMoraleCur() {
        return moraleCur;
    }

    public void setMoraleCur(int moraleCur) {
        this.moraleCur = moraleCur;
    }

    // ===================== 业务方法 =====================
    private BattleUnit(BattleTeam team, int unitIndex) {
        this.unitIndex = unitIndex;
        int unitHang = unitIndex % BattleUtils.HANG_COUNT;
        this.unitHang = unitHang != 0 ? unitHang : BattleUtils.HANG_COUNT;
        this.team = team;
    }

    public static BattleUnit gen(AbstractRole role, BattleTeam team, int unitIndex, boolean isFullHp) {
        BattleUnit unit = new BattleUnit(team, unitIndex);
        unit.name = role.getNickname();
        unit.level = role.getLevel();
        // 战斗单元最初数值属性
        unit.baseStrengthAttack = role.getStrengthAttack();
        unit.baseStuntAttack = role.getStuntAttack();
        unit.baseMagicAttack = role.getMagicAttack();
        unit.baseStrengthDefense = role.getStrengthDefense();
        unit.baseStuntDefense = role.getStuntDefense();
        unit.baseMagicDefense = role.getMagicDefense();
        unit.baseHpMax = role.getHpMax();
        unit.baseCrit = role.getCrit();
        unit.baseHit = role.getHit();
        unit.basePoJi = role.getPoJi();
        unit.baseBiSha = role.getBiSha();
        unit.baseToughness = role.getToughness();
        unit.baseDodge = role.getDodge();
        unit.baseBlock = role.getBlock();
        // 战斗中计算后战斗数值属性
        unit.recountProperties();
        if (isFullHp) {
            unit.hpCur = unit.hpMax;
        } else {
            unit.hpCur = role.getHpCur();
        }
        unit.moraleCur = 100; // TODO 为了测试方便
        // 技能
        unit.vocationSkill = VocationTemplate.get(role.getVocation()).getSkill();
        unit.specialSkill = SkillTemplate.getItemTemplate(role.getSpecialSkill());
        return unit;
    }

    public void recountProperties() {
        double rate;
        double attackRate = (getBuffDebuffValue(SkillDef.Effect.BUFF_ATTACK_ALL_ADD_RATE)
                - getBuffDebuffValue(SkillDef.Effect.DEBUFF_ATTACK_ALL_REDUCE_RATE)) / BattleUtils.BUFF_RATE_BASE;
        double defenseRate = (getBuffDebuffValue(SkillDef.Effect.BUFF_DEFENSE_ALL_ADD_RATE)
                - getBuffDebuffValue(SkillDef.Effect.DEBUFF_DEFENSE_ALL_REDUCE_RATE)) / BattleUtils.BUFF_RATE_BASE;
        // 普通攻击
        rate = 1D + attackRate + (getBuffDebuffValue(SkillDef.Effect.BUFF_STRENGTH_ATTACK_ADD_RATE)
                - getBuffDebuffValue(SkillDef.Effect.DEBUFF_STRENGTH_ATTACK_REDUCE_RATE)) / BattleUtils.BUFF_RATE_BASE;
        strengthAttack = MathUtils.ceil2Int(baseStrengthAttack * rate);
        // 绝技攻击
        rate = 1D + attackRate + (getBuffDebuffValue(SkillDef.Effect.BUFF_STUNT_ATTACK_ADD_RATE)
                - getBuffDebuffValue(SkillDef.Effect.DEBUFF_STUNT_ATTACK_REDUCE_RATE)) / BattleUtils.BUFF_RATE_BASE;
        stuntAttack = MathUtils.ceil2Int(baseStuntAttack * rate);
        // 绝技攻击
        rate = 1D + attackRate + (getBuffDebuffValue(SkillDef.Effect.BUFF_MAGIC_ATTACK_ADD_RATE)
                - getBuffDebuffValue(SkillDef.Effect.DEBUFF_MAGIC_ATTACK_REDUCE_RATE)) / BattleUtils.BUFF_RATE_BASE;
        magicAttack = MathUtils.ceil2Int(baseMagicAttack * rate);
        // 防御
        if (hasBuffDebuff(SkillDef.Effect.DEBUFF_DEFENSE_ALL_ZERO)) {
            strengthDefense = stuntDefense = magicDefense = 0;
        } else {
            // 普通防御
            rate = 1D + defenseRate + (getBuffDebuffValue(SkillDef.Effect.BUFF_STRENGTH_DEFENSE_ADD_RATE)
                    - getBuffDebuffValue(SkillDef.Effect.DEBUFF_STRENGTH_DEFENSE_REDUCE_RATE)) / BattleUtils.BUFF_RATE_BASE;
            strengthDefense = MathUtils.ceil2Int(baseStrengthDefense * rate);
            // 绝技防御
            rate = 1D + defenseRate + (getBuffDebuffValue(SkillDef.Effect.BUFF_STUNT_DEFENSE_ADD_RATE)
                    - getBuffDebuffValue(SkillDef.Effect.DEBUFF_STUNT_DEFENSE_REDUCE_RATE)) / BattleUtils.BUFF_RATE_BASE;
            stuntDefense = MathUtils.ceil2Int(baseStuntDefense * rate);
            // 绝技防御
            rate = 1D + defenseRate + (getBuffDebuffValue(SkillDef.Effect.BUFF_MAGIC_DEFENSE_ADD_RATE)
                    - getBuffDebuffValue(SkillDef.Effect.DEBUFF_MAGIC_DEFENSE_REDUCE_RATE)) / BattleUtils.BUFF_RATE_BASE;
            magicDefense = MathUtils.ceil2Int(baseMagicDefense * rate);
        }
        // 最大血量(暂时不考虑buff、debuff)
        hpMax = baseHpMax;
        // 暴击
        crit = baseCrit + getBuffDebuffValue(SkillDef.Effect.BUFF_CRIT_ADD_RATE)
                - getBuffDebuffValue(SkillDef.Effect.DEBUFF_CRIT_REDUCE_RATE);
        // 命中
        if (hasBuffDebuff(SkillDef.Effect.DEBUFF_HIT_ZERO)) {
            hit = 0;
        } else {
            hit = baseHit + getBuffDebuffValue(SkillDef.Effect.BUFF_HIT_ADD_RATE)
                    - getBuffDebuffValue(SkillDef.Effect.DEBUFF_HIT_REDUCE_RATE);
        }
        // 破击
        poJi = basePoJi + getBuffDebuffValue(SkillDef.Effect.BUFF_POJI_ADD_RATE)
                - getBuffDebuffValue(SkillDef.Effect.DEBUFF_POJI_REDUCE_RATE);
        // 必杀
        biSha = baseBiSha + getBuffDebuffValue(SkillDef.Effect.BUFF_BISHA_ADD_RATE)
                - getBuffDebuffValue(SkillDef.Effect.DEBUFF_BISHA_REDUCE_RATE);
        // 韧性
        toughness = baseToughness + getBuffDebuffValue(SkillDef.Effect.BUFF_TOUGHNESS_ADD_RATE)
                - getBuffDebuffValue(SkillDef.Effect.DEBUFF_TOUGHNESS_REDUCE_RATE);
        // 闪避
        dodge = baseDodge + getBuffDebuffValue(SkillDef.Effect.BUFF_DODGE_ADD_RATE)
                - getBuffDebuffValue(SkillDef.Effect.DEBUFF_DODGE_REDUCE_RATE);
        // 格挡
        block = baseBlock + getBuffDebuffValue(SkillDef.Effect.BUFF_BLOCK_ADD_RATE)
                - getBuffDebuffValue(SkillDef.Effect.DEBUFF_BLOCK_REDUCE_RATE);
    }

//    private void addTempImpact() {
//        addImpact(tempImpacts);
//    }
//
//    private void addContinualImpacts() {
//        addImpact(continualImpacts);
//    }

    private void addImpact(SkillImpactInfoVO impact) {
        int round = impact.getRound();
        Map<SkillImpactInfoVO, Integer> impacts = round == SkillImpactInfoVO.ROUND_TEMP ?
                tempImpacts : continualImpacts;
        // 移除已存在的该技能效果
        boolean hasImpact = impacts.containsKey(impact);
        if (hasImpact) {
            impacts.remove(impact);
            clearImpact(impact);
        }
        // 增加效果

    }

    public void clearImpact(SkillImpactInfoVO impact) {
        for (int i = 0, len = impact.getEffects().size(); i < len; i++) {
            SkillDef.Effect effect = impact.getEffect(i);
            int param = impact.getParam(i);
            if (effect.getType() == SkillDef.EffectType.BUFF_DEBUFF) {
                int value = buffDebuffValues.get(effect);
                value -= param;
                if (value > 0) {
                    buffDebuffValues.put(effect, value);
                } else {
                    buffDebuffValues.remove(effect);
                }
            }
        }
    }

    private int getBuffDebuffValue(SkillDef.Effect effect) {
        return buffDebuffValues.get(effect);
    }

    public boolean hasBuffDebuff(SkillDef.Effect effect) {
        return buffDebuffValues.containsKey(effect);
    }

    public boolean isAlive() {
        return hpCur > 0;
    }

    public void doAction(BaseBattleOperation operation, BattleAction roundAction) {
        BattleUnitAction unitAction = new BattleUnitAction(unitIndex);
        doHotDot(operation, unitAction);
        doClearImpact(operation, unitAction);
        doSkill(operation, unitAction);
        if (!unitAction.isNullAction()) {
            roundAction.addUnitAction(unitAction);
        }
    }

    private void doHotDot(BaseBattleOperation operation, BattleUnitAction unitAction) {

    }

    private void doClearImpact(BaseBattleOperation operation, BattleUnitAction unitAction) {

    }

    private void doSkill(BaseBattleOperation operation, BattleUnitAction unitAction) {
        // 晕眩无法释放技能
        if (hasBuffDebuff(SkillDef.Effect.DEBUFF_STUN)) {
            return;
        }
        // 获得技能、查找技能目标
        SkillTemplate skill = findSkill();
        List<BattleUnit> targets = findSkillTargets(operation, skill);
        if (targets.isEmpty()) { // 当没目标时候，不释放技能
            return;
        }
        // 技能之前的效果
        if (!skill.getBeforeImpacts().isEmpty()) {
            for (SkillImpactInfoVO impact : skill.getBeforeImpacts()) {
//                for (SkillDef.Effect effect : impact.getEffects()) {
//
//                }
                if (impact.effect()) {
                    continue;
                }
//                doSkillImpact(impact, targets);
                // todo 明天从这里开始
            }
        }
        // 攻击敌人
        // 技能之后的效果
    }

    private void doSkillImpact(SkillImpactInfoVO impact, List<BattleUnit> targets) {
        boolean isBeforeAttack = impact.getTime() == SkillDef.ImpactTime.BEFORE_ATTACK;
        boolean isSelfTarget = impact.getTarget() == SkillDef.ImpactTarget.SELF;
        for (int i = 0, len = impact.getEffects().size(); i < len; i++) {
            SkillDef.Effect effect = impact.getEffect(i);
            int param = impact.getParam(i);
            if (isSelfTarget) {
//                doSkillImpactEffect(this, effect, param, impact.getRound());

            } else {

            }
        }
    }

    private void doSkillImpactEffect(BattleUnit targetUnit, SkillDef.Effect effect, int param, int round) {
        SkillDef.EffectType effectType = effect.getType();
        switch (effectType) {
            case BUFF_DEBUFF:
                if (round == SkillImpactInfoVO.ROUND_TEMP) {
//                    targetUnit
                } else {

                }
                break;
            case HOT_DOT:
                break;
            case FUNCTION:
                break;
        }
    }

    /**
     * @return 当前可使用的技能
     */
    private SkillTemplate findSkill() {
        return moraleCur >= specialSkill.getNeedMorale() ? specialSkill : vocationSkill;
    }

    /**
     * 寻找技能目标：
     * <pre>
     *     1. 通过【攻击范围】+【目标】筛选出可以攻击的目标数组
     *     2. 通过【查找目标顺序】进行筛选出来的目标数组排序
     *     3. 从数组中选择【目标人数】个目标进行攻击
     * </pre>
     * 特殊逻辑：
     * <pre>
     *     1. 隐身{@link org.yunai.swjg.server.module.skill.SkillDef.Effect#BUFF_CLOAK}的单位，无法作为目标
     *     2. 当处于混乱{@link org.yunai.swjg.server.module.skill.SkillDef.Effect#DEBUFF_CHAOS}时，无法拿自己当目标。
     * </pre>
     * TODO:
     * 该方式下寻找会有个无法解决的，当攻击范围为【目标周围，半径为1】时+查询目标顺序为【随即】。
     * 该情况下，其实应该是先随即找到目标，在寻找其他的。如果真的需要，在改下这里实现好了。
     *
     * @param operation 战斗操作对象
     * @param skill     技能
     * @return 技能目标
     */
    private List<BattleUnit> findSkillTargets(BaseBattleOperation operation, SkillTemplate skill) {
        // 根据【攻击范围】+【目标】筛选出可以攻击的目标数组
        List<BattleUnit> scopeTargets = new ArrayList<>(); // 在范围中的目标
        SkillDef.Target target = skill.getTarget();
        if (hasBuffDebuff(SkillDef.Effect.DEBUFF_CHAOS)) {
            target = target.getChaosTarget();
        }
        switch (target) {
            case SELF:
                scopeTargets.add(this);
                break;
            case ENEMY:
                findSkillScopeTargets(skill, scopeTargets, operation.getAttackTeam() != team ?
                        operation.getAttackTeam() : operation.getDefenseTeam());
                break;
            case TEAM:
                findSkillScopeTargets(skill, scopeTargets, team);
                break;
            case NONE:
                break;
        }
        // 处理下隐身的buff
        filterSkillScopeTargets(scopeTargets);
        // 排序目标
        switch (skill.getTargetSort()) {
            case INDEX_ASC:
            case INDEX_DESC:
            case NEXT:
            case MORALE_DESC:
            case HP_ASC:
                Collections.sort(scopeTargets, skill.getTargetSort().getComparator());
                break;
            case RANDOM:
                Collections.shuffle(scopeTargets);
                break;
        }
        // 获得最终攻击目标数组
        List<BattleUnit> targets = new ArrayList<>(skill.getMaxTarget());
        if (skill.getMaxTarget() == 1 && hasBuffDebuff(SkillDef.Effect.DEBUFF_CHAOS)) { // 处理混乱时，单体攻击不攻击自己
            BattleUnit firstUnit = scopeTargets.get(0);
            if (this == firstUnit) {
                if (scopeTargets.size() > 1) {
                    targets.add(scopeTargets.get(1));
                }
            } else {
                targets.add(firstUnit);
            }
        } else {
            targets.addAll(scopeTargets.subList(0, skill.getMaxTarget()));
        }
        return targets;
    }

    /**
     * 从目标队伍里查找目标对象
     *
     * @param skill        技能
     * @param scopeTargets 目标对象数组
     * @param team         队伍
     */
    private void findSkillScopeTargets(SkillTemplate skill, List<BattleUnit> scopeTargets, BattleTeam team) {
        switch (skill.getScope()) {
            case HANG:
                findSkillHangScopeTargets(skill, scopeTargets, team);
                break;
            case LIE:
                findSkillLieScopeTargets(skill, scopeTargets, team);
                break;
            case ALL:
                findSkillAllScopeTargets(skill, scopeTargets, team);
                break;
            case ROUND:
                throw new Error("暂时不实现！");
        }
    }

    /**
     * 按照{@link org.yunai.swjg.server.module.skill.SkillDef.Scope#HANG}从目标队伍里查找目标对象
     *
     * @param skill        技能
     * @param scopeTargets 目标对象数组
     * @param team         队伍
     */
    private void findSkillHangScopeTargets(SkillTemplate skill, List<BattleUnit> scopeTargets, BattleTeam team) {
        int[] hangScope = BattleUtils.SCOPE_HANG[unitHang];
        for (int i = 1; i <= BattleUtils.HANG_COUNT; i++) {
            List<BattleUnit> units = team.getHangAlives(hangScope[i]);
            if (!units.isEmpty()) {
                scopeTargets.addAll(units);
                return;
            }
        }
    }

    /**
     * 按照{@link org.yunai.swjg.server.module.skill.SkillDef.Scope#LIE}从目标队伍里查找目标对象
     *
     * @param skill        技能
     * @param scopeTargets 目标对象数组
     * @param team         队伍
     */
    private void findSkillLieScopeTargets(SkillTemplate skill, List<BattleUnit> scopeTargets, BattleTeam team) {
        for (int i = 1; i <= BattleUtils.LIE_COUNT; i++) {
            List<BattleUnit> units = team.getLieAlives(i);
            if (!units.isEmpty()) {
                scopeTargets.addAll(units);
                return;
            }
        }
    }

    /**
     * 按照{@link org.yunai.swjg.server.module.skill.SkillDef.Scope#ALL}从目标队伍里查找目标对象
     *
     * @param skill        技能
     * @param scopeTargets 目标对象数组
     * @param team         队伍
     */
    private void findSkillAllScopeTargets(SkillTemplate skill, List<BattleUnit> scopeTargets, BattleTeam team) {
        scopeTargets.addAll(team.getAllAlives());
    }

    /**
     * 过滤次目标对象数组
     * <pre>
     *     1. 拥有{@link org.yunai.swjg.server.module.skill.SkillDef.Effect#BUFF_CLOAK}的对象
     * </pre>
     *
     * @param scopeTargets 目标对象数组
     */
    private void filterSkillScopeTargets(List<BattleUnit> scopeTargets) {
        Iterator<BattleUnit> iterator = scopeTargets.iterator();
        while (iterator.hasNext()) {
            if (iterator.next().hasBuffDebuff(SkillDef.Effect.BUFF_CLOAK)) {
                iterator.remove();
            }
        }
    }
}